/*
 * Copyright (C) 2008 The Android Open Source Project
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *  * Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *  * Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

/** @defgroup dirent Dirent
 * @ingroup libc
 */

#ifndef _DIRENT_H_
#define _DIRENT_H_

#include <stdint.h>
#include <sys/cdefs.h>

#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif /* __cplusplus */
#endif /* __cplusplus */


#ifndef DT_UNKNOWN
#define DT_UNKNOWN 0
#define DT_FIFO 1
#define DT_CHR 2
#define DT_DIR 4
#define DT_BLK 6
#define DT_REG 8
#define DT_LNK 10
#define DT_SOCK 12
#define DT_WHT 14
#endif

#define __DIRENT64_BODY \
    uint64_t         d_ino; \
    int64_t          d_off; \
    unsigned short   d_reclen; \
    unsigned char    d_type; \
    char             d_name[256]; \

struct dirent { __DIRENT64_BODY };
struct dirent64 { __DIRENT64_BODY };

#undef __DIRENT64_BODY

/* glibc compatibility. */
#undef _DIRENT_HAVE_D_NAMLEN /* Linux doesn't have a d_namlen field. */
#define _DIRENT_HAVE_D_RECLEN
#define _DIRENT_HAVE_D_OFF
#define _DIRENT_HAVE_D_TYPE

#define d_fileno d_ino

typedef struct DIR DIR;

/**
* @ingroup dirent
*
* @par Description:
* The opendir() function shall open a directory stream corresponding to the directory named by the path argument.
* The directory stream is positioned at the first entry. If the type DIR is implemented using a file descriptor,
* applications shall only be able to open up to a total of {OPEN_MAX} files and directories.
*
* @param  path [IN] path of the diretory which need to open.
*
* @attention
* <ul>
* <li>None.</li>
* </ul>
*
* @retval #DIR* Upon successful completion, these functions shall return a pointer to an object of type DIR.
* @retval #NULL An error is encountered and open the directory faild.
*
* @par Errors
* <ul>
* <li><b>EINVAL</b>: The path is an empty string.</li>
* <li><b>ENAMETOOLONG</b>: The length of a component of a pathname is longer than {NAME_MAX}.</li>
* <li><b>ENOENT</b>: A component of the path does not exist.</li>
* <li><b>ENOMEM</b>: Out of memory.</li>
* <li><b>ENOTDIR</b>: A component of the path is not a directory.</li>
* <li><b>EMFILE</b>: Too many open file.</li>
* <li><b>EROFS</b>: The physical drive is write protected with fat filesystem.</li>
* <li><b>EIO</b>: A hard error occurred in the low level disk I/O layer or the physical drive cannot work.</li>
* <li><b>ENODEV</b>: The mount is not healthy.</li>
* <li><b>EPERM</b>: Other errors.</li>
* </ul>
*
* @par Dependency:
* <ul><li>dirent.h</li></ul>
* @see open | readdir | rewinddir | closedir
* @since Huawei LiteOS V100R001C00
*/
extern DIR* opendir(const char *path);
extern DIR* fdopendir(int);

/**
* @ingroup dirent
*
* @par Description:
* The readdir() function shall return a pointer to a structure representing the directory entry
* at the current position in the directory stream specified by the argument dirp,
* and position the directory stream at the next entry.
* It shall return a null pointer upon reaching the end of the directory stream.
*
* @param  dirp [IN] a directory stream of current directory.
*
* @attention
* <ul>
* <li>None.</li>
* </ul>
*
* @retval "struct dirent*"  Upon successful completion, readdir() shall return a pointer to an object of type struct dirent.
* @retval "NULL"            An error is encountered or the end of the directory is encountered.
*
* @par Errors
* <ul>
* <li><b>EINVAL</b>: dirp argument is invalid.</li>
* <li><b>ENAMETOOLONG</b>: The length of the pathname of the current directory entry is longer than {NAME_MAX}.</li>
* <li><b>ENOENT</b>: The current position of the directory stream is invalid.</li>
* <li><b>ENOMEM</b>: Out of memory.</li>
* <li><b>ENOSPC</b>: No free cluster of fat filesystem.</li>
* <li><b>EBADF</b>: The dirp argument does not refer to an open directory stream.</li>
* <li><b>EIO</b>: A hard error occurred in the low level disk I/O layer or the physical drive cannot work.</li>
* <li><b>ENODEV</b>: The mount is not healthy.</li>
* <li><b>EACCES</b>: The current file system doesn't support readdir.</li>
* <li><b>EPERM</b>: Other errors.</li>
* </ul>
*
* @par Dependency:
* <ul><li>dirent.h</li></ul>
* @see closedir | rewinddir
* @since Huawei LiteOS V100R001C00
*/
extern struct dirent* readdir(DIR *dirp);
extern struct dirent64* readdir64(DIR*);
extern int readdir_r(DIR*, struct dirent*, struct dirent**);
extern int readdir64_r(DIR*, struct dirent64*, struct dirent64**);
/**
* @ingroup dirent
*
* @par Description:
* The closedir() function shall close the directory stream referred to by the argument dirp.
*
* @param  dirp [IN] An instance of type DIR created by a previous call to opendir().
*
* @attention
* <ul>
* <li>None.</li>
* </ul>
*
* @retval #0  Close directory successful.
* @retval #-1 An error is encountered and close the directory failed.
*
* @par Errors
* <ul>
* <li><b>EBADF</b>: The dirp argument does not refer to an open directory stream.</li>
* <li><b>EEXIST</b> : The 1st member in the FIL/DIR object is invalid of fat.</li>
* <li><b>EIO</b>: A hard error occurred in the low level disk I/O layer or the physical drive cannot work.</li>
* <li><b>ENOENT</b>: The internal node pointed to by DIR doesn't exist in jffs2 and romfs.</li>
* <li><b>EPERM</b>: Other errors.</li>
* </ul>
*
* @par Dependency:
* <ul><li>dirent.h</li></ul>
* @see None
* @since Huawei LiteOS V100R001C00
*/
extern int closedir(DIR *dirp);

/**
* @ingroup dirent
*
* @par Description:
* The rewinddir() function shall reset the position of the directory stream to
* which dirp refers to the beginning of the directory.
*
* @param  dirp [IN] An instance of type DIR created by a previous call to opendir().
*
* @attention
* <ul>
* <li>None.</li>
* </ul>
*
* @retval #void None.
*
* @par Errors
* <ul>
* <li><b>EBADF</b>: The dirp argument does not refer to an open directory stream.</li>
* </ul>
*
* @par Dependency:
* <ul><li>dirent.h</li></ul>
* @see  readdir | closedir
* @since Huawei LiteOS V100R001C00
*/
extern void rewinddir(DIR *dirp);

/**
* @ingroup dirent
*
* @par Description:
* The seekdir() function shall set the position of the next readdir() operation on the directory stream specified
* by dirp to the position specified by offset. The value of offset should have been returned from
* an earlier call to telldir() using the same directory stream.
*
* @param  dirp   [IN] An instance of type DIR created by a previous call to opendir().
* @param  offset [IN] offset to seek to
*
* @attention
* <ul>
* <li>None.</li>
* </ul>
*
* @retval #void None.
*
* @par Errors
* <ul>
* <li><b>EBADF</b>: The dirp argument does not refer to an open directory stream.</li>
* <li><b>EINVAL</b>: offset is less than zero.</li>
* </ul>
*
* @par Dependency:
* <ul><li>dirent.h</li></ul>
* @see  readdir | telldir
* @since Huawei LiteOS V100R001C00
*/
extern void seekdir(DIR *dirp, long offset);

/**
* @ingroup dirent
*
* @par Description:
* The telldir() function shall obtain the current location associated with the directory stream specified by dirp.
*
* @param  dirp [IN] An instance of type DIR created by a previous call to opendir().
*
* @attention
* <ul>
* <li>None.</li>
* </ul>
*
* @retval #long Upon successful completion, telldir() shall return the current location
* of the specified directory stream.
*
* @par Errors
* <ul>
* <li><b>EBADF</b>: The dirp argument does not refer to an open directory stream.</li>
* </ul>
*
* @par Dependency:
* <ul><li>dirent.h</li></ul>
* @see  readdir | seekdir
* @since Huawei LiteOS V100R001C00
*/
extern long telldir(DIR *dirp);
extern int dirfd(DIR*);

/**
* @ingroup dirent
*
* @par Description:
* The alphasort() function can be used as the comparison function for the scandir() function
* to sort the directory entries, d1 and d2, into alphabetical order
*
* @attention
* <ul>
* <li>None.</li>
* </ul>
*
* @retval #int Upon successful completion, the alphasort() function shall return an integer greater than,
* equal to, or less than 0, according to whether the name of the directory entry pointed to by d1
* is lexically greater than, equal to, or less than the directory pointed to by d2 when both are interpreted
* as appropriate to the current locale. There is no return value reserved to indicate an error.
*
* @par Dependency:
* <ul><li>dirent.h</li></ul>
* @see  strcoll
* @since Huawei LiteOS V100R001C00
*/
extern int alphasort(const struct dirent**, const struct dirent**);
extern int alphasort64(const struct dirent64**, const struct dirent64**);
extern int scandir64(const char*, struct dirent64***, int (*)(const struct dirent64*), int (*)(const struct dirent64**, const struct dirent64**));

/**
* @ingroup dirent
*
* @par Description:
* The scandir() function shall scan the directory dir, calling the function referenced by filter on each directory
* entry. Entries for which the function referenced by filter returns non-zero shall be stored in strings allocated
* as if by a call to malloc(), and sorted as if by a call to qsort() with the comparison function compar,
* except that compar need not provide total ordering. The strings are collected in array namelist
* which shall be allocated as if by a call to malloc(). If filter is a null pointer, all entries shall be selected.
* If the comparison function compar does not provide total ordering, the order in which the directory entries
* are stored is unspecified.
*
* @param  dir      [IN]  The path of the directory need to scan.
* @param  namelist [OUT] Return the pointer of type struct dirent* to store the dirent scanned in the directory.
* @param  filter   [IN]  Refer to the function to select the entries.
* @param  compar   [IN]  The comparison function used in qsort() to sort the entries.
*
* @attention
* <ul>
* <li>None.</li>
* </ul>
*
* @retval #int the number of entries in the array and a pointer to the array through the parameter namelist.
* @retval #-1 An error is encountered.
*
* @par Errors
* <ul>
* <li><b>EINVAL</b>: The path is an empty string.</li>
* <li><b>ENAMETOOLONG</b>: The length of a component of a pathname is longer than {NAME_MAX}.</li>
* <li><b>ENOENT</b>: A component of the path does not exist.</li>
* <li><b>ENOMEM</b>: Out of memory.</li>
* <li><b>ENOSPC</b>: Out of memory in ramfs filesystem.</li>
* <li><b>ENOTDIR</b>: A component of the path is not a directory.</li>
* <li><b>EMFILE</b>: Too many open file.</li>
* <li><b>EROFS</b>: The physical drive is write protected with fat filesystem.</li>
* <li><b>EIO</b>: A hard error occurred in the low level disk I/O layer or the physical drive cannot work.</li>
* <li><b>ENODEV</b>: The mount is not healthy.</li>
* <li><b>EPERM</b>: Other errors.</li>
* </ul>
*
* @par Dependency:
* <ul><li>dirent.h</li></ul>
* @see  qsort
* @since Huawei LiteOS V100R001C00
*/
extern int scandir(const char *dir, struct dirent*** namelist,
    int (*filter)(const struct dirent*), int (*compar)(const struct dirent**, const struct dirent**));

#if defined(__USE_GNU)
int scandirat64(int, const char*, struct dirent64***, int (*)(const struct dirent64*), int (*)(const struct dirent64**, const struct dirent64**));
int scandirat(int, const char*, struct dirent***, int (*)(const struct dirent*), int (*)(const struct dirent**, const struct dirent**));
#endif


#ifdef __cplusplus
#if __cplusplus
}
#endif /* __cplusplus */
#endif /* __cplusplus */

#endif /* _DIRENT_H_ */
